from lxml import etree
from typing import List
import ast


class Bounds:
    def __init__(self, left: int, top: int, right: int, bottom: int):
        self.left = left
        self.top = top
        self.right = right
        self.bottom = bottom
        self.center_x = int((left + right) / 2)
        self.center_y = int((top + bottom) / 2)

    def __str__(self):
        return f"left={self.left},top={self.top},right={self.right},bottom={self.bottom},center=({self.center_x},{self.center_y})"


class UiNode:

    @staticmethod
    def from_xml(xml: str):
        try:
            return UiNode(etree.fromstring(xml))
        except Exception as e:
            print('xmli处理n异常',e)
            return UiNode(etree.fromstring("<node bounds=\"[0,0,0,0]\"></node>"))

    def __init__(self, node):
        self.node = node
        bounds = ast.literal_eval(node.get("bounds"))
        self.bounds = Bounds(bounds[0], bounds[1], bounds[2], bounds[3])

    def get_attr(self, name: str) -> str:
        """
        获取节点的属性

        name: 属性的名称
        """
        return self.node.get(name)

    def get_class_attr(self) -> str:
        """
        获取节点的class属性

        """
        return self.get_attr("class")

    def get_text_attr(self) -> str:
        """
        获取节点的text属性

        """
        return self.get_attr("text")

    def get_desc_attr(self) -> str:
        """
        获取节点的content-desc属性

        """
        return self.get_attr("content-desc")

    def get_bounds(self) -> Bounds:
        """
        获取节点的bounds

        """
        return self.bounds

    def list_by_text(self, text: str):
        """
        匹配所有子节点中text属性等于指定内容的节点

        text: 匹配的文本内容
        """
        finds = self.node.xpath(f'.//node[@text="{text}"]')
        all: List[UiNode] = []
        for node in finds:
            all.append(UiNode(node=node))
        return all

    def list_by_contain_text(self, text: str):
        """
        匹配所有子节点中text属性包含指定内容的节点

        text: 匹配的文本内容
        """
        finds = self.node.xpath(f'.//node[contains(@text,"{text}")]')
        all: List[UiNode] = []
        for node in finds:
            all.append(UiNode(node=node))
        return all

    def find_by_text(self, text: str):
        """
        匹配第一个子节点text属性等于指定内容的节点

        text: 匹配的文本内容
        """
        finds = self.node.xpath(f'.//node[1][@text="{text}"]')
        if len(finds):
            return UiNode(finds[0])
        return None

    def list_by_desc(self, desc: str):
        """
        匹配所有子节点中content-desc属性等于指定内容的节点

        desc: 匹配的desc内容
        """
        finds = self.node.xpath(f'.//node[@content-desc="{desc}"]')
        all: List[UiNode] = []
        for node in finds:
            all.append(UiNode(node=node))
        return all

    def list_by_contain_desc(self, desc: str):
        """
        匹配所有子节点中content-desc属性包含指定内容的节点

        desc: 匹配的文本内容
        """
        finds = self.node.xpath(f'.//node[contains(@content-desc,"{desc}")]')
        all: List[UiNode] = []
        for node in finds:
            all.append(UiNode(node=node))
        return all

    def find_by_desc(self, desc: str):
        """
        匹配第一个子节点content-desc属性等于指定内容的节点

        desc: 匹配的desc内容
        """
        finds = self.node.xpath(f'.//node[1][@content-desc="{desc}"]')
        if len(finds):
            return UiNode(finds[0])
        return None

    def list_by_clazz(self, clazz: str):
        """
        匹配所有子节点中class属性等于指定内容的节点

        clazz: 匹配的class
        """
        finds = self.node.xpath(f'.//node[@class="{clazz}"]')
        all: List[UiNode] = []
        for node in finds:
            all.append(UiNode(node=node))
        return all

    def find_by_class(self, clazz: str):
        """
        匹配第一个子节点class属性等于指定内容的节点

        clazz: 匹配的class
        """
        finds = self.node.xpath(f'.//node[1][@class="{clazz}"]')
        if len(finds):
            return UiNode(finds[0])
        return None


if __name__ == "__main__":
    # 初始化
    xml = """
    <node class="android.widget.FrameLayout" bounds="[0,0,1080,2160]" text="null" content-desc="null" clickable="false" scrollable="false" editable="false">
        <node class="android.widget.LinearLayout" bounds="[0,0,1080,2118]" text="null" content-desc="null" clickable="false" scrollable="false" editable="false">
            <node class="android.widget.FrameLayout" bounds="[0,63,1080,2118]" text="null" content-desc="null" clickable="false" scrollable="false" editable="false">
            <node class="android.view.ViewGroup" bounds="[0,63,1080,2118]" text="null" content-desc="null" clickable="false" scrollable="false" editable="false">
                <node class="android.widget.FrameLayout" bounds="[0,63,1080,210]" text="null" content-desc="null" clickable="false" scrollable="false" editable="false">
                <node class="android.view.ViewGroup" bounds="[0,63,1080,210]" text="null" content-desc="null" clickable="false" scrollable="false" editable="false">
                    <node class="android.widget.TextView" bounds="[42,101,258,172]" text="自动助手" content-desc="null" clickable="false" scrollable="false" editable="false">
                    </node>            <node class="androidx.appcompat.widget.LinearLayoutCompat" bounds="[1080,63,1080,210]" text="null" content-desc="null" clickable="false" scrollable="false" editable="false">
                    </node>          </node>        </node>        <node class="android.widget.FrameLayout" bounds="[0,210,1080,2118]" text="null" content-desc="null" clickable="false" scrollable="false" editable="false">
                <node class="android.widget.LinearLayout" bounds="[0,210,1080,2118]" text="null" content-desc="null" clickable="false" scrollable="false" editable="false">
                    <node class="android.widget.FrameLayout" bounds="[63,273,1017,550]" text="null" content-desc="null" clickable="false" scrollable="false" editable="false">
                    <node class="android.widget.LinearLayout" bounds="[86,302,994,521]" text="null" content-desc="null" clickable="false" scrollable="false" editable="false">
                        <node class="android.widget.TextView" bounds="[128,344,269,407]" text="设备号" content-desc="null" clickable="false" scrollable="false" editable="false">
                        </node>                <node class="android.widget.TextView" bounds="[128,428,254,479]" text="931292" content-desc="null" clickable="false" scrollable="false" editable="false">
                        </node>              </node>            </node>            <node class="android.widget.FrameLayout" bounds="[63,550,1017,995]" text="null" content-desc="null" clickable="false" scrollable="false" editable="false">
                    <node class="android.widget.LinearLayout" bounds="[86,579,994,966]" text="null" content-desc="null" clickable="false" scrollable="false" editable="false">
                        <node class="android.widget.TextView" bounds="[128,621,363,684]" text="无障碍服务" content-desc="null" clickable="false" scrollable="false" editable="false">
                        </node>                <node class="android.widget.TextView" bounds="[128,705,517,756]" text="无障碍服务状态: 已启用" content-desc="null" clickable="false" scrollable="false" editable="false">
                        </node>                <node class="android.widget.Button" bounds="[128,798,952,924]" text="打开无障碍设置" content-desc="null" clickable="true" scrollable="false" editable="false">
                        </node>              </node>            </node>            <node class="android.widget.FrameLayout" bounds="[63,995,1017,1440]" text="null" content-desc="null" clickable="false" scrollable="false" editable="false">
                    <node class="android.widget.LinearLayout" bounds="[86,1024,994,1411]" text="null" content-desc="null" clickable="false" scrollable="false" editable="false">
                        <node class="android.widget.TextView" bounds="[128,1066,316,1129]" text="截屏权限" content-desc="null" clickable="false" scrollable="false" editable="false">
                        </node>                <node class="android.widget.TextView" bounds="[128,1150,480,1201]" text="截屏权限状态: 未授予" content-desc="null" clickable="false" scrollable="false" editable="false">
                        </node>                <node class="android.widget.Button" bounds="[128,1243,952,1369]" text="申请截屏权限" content-desc="null" clickable="true" scrollable="false" editable="false">
                        </node>              </node>            </node>            <node class="android.widget.FrameLayout" bounds="[63,1440,1017,2012]" text="null" content-desc="null" clickable="false" scrollable="false" editable="false">
                    <node class="android.widget.LinearLayout" bounds="[86,1469,994,1983]" text="null" content-desc="null" clickable="false" scrollable="false" editable="false">
                        <node class="android.widget.TextView" bounds="[128,1511,316,1574]" text="服务状态" content-desc="null" clickable="false" scrollable="false" editable="false">
                        </node>                <node class="android.widget.EditText" bounds="[128,1595,952,1701]" text="121.37.213.206" content-desc="null" clickable="true" scrollable="false" editable="true">
                        </node>                <node class="android.widget.TextView" bounds="[128,1722,480,1773]" text="服务运行状态: 运行中" content-desc="null" clickable="false" scrollable="false" editable="false">
                        </node>                <node class="android.widget.LinearLayout" bounds="[128,1773,952,1941]" text="null" content-desc="null" clickable="false" scrollable="false" editable="false">
                        <node class="android.widget.Button" bounds="[133,1815,535,1941]" text="启动服务" content-desc="null" clickable="true" scrollable="false" editable="false">
                        </node>                  <node class="android.widget.Button" bounds="[545,1815,947,1941]" text="停止服务" content-desc="null" clickable="true" scrollable="false" editable="false">
                        </node>                </node>              </node>            </node>          </node>        </node>      </node>    </node>  </node>  <node class="android.view.View" bounds="[0,0,1080,63]" text="null" content-desc="null" clickable="false" scrollable="false" editable="false">
        </node>  <node class="android.view.View" bounds="[0,2118,1080,2160]" text="null" content-desc="null" clickable="false" scrollable="false" editable="false">
        </node></node>
        """

    node = UiNode.from_xml(xml=xml)
